package com.yimi.appstore.download;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.database.Cursor;
import android.os.Environment;

import com.yimi.appstore.db.dao.DownloadRecordEntity;
import com.yimi.appstore.db.dao.DownloadRecordEntityManager;
import com.yimi.appstore.download.DownloadTask.OnChangeListener;

public class DownloadManager {
	private final String TAG = "DownloadManager";
	public static String APP_PATH = Environment.getExternalStorageDirectory()
			+ "/YimiAppStore/download/";
	private final int DUPLICATE_BEGIN_INDEX = 2;
	private final Pattern fPattern = Pattern.compile("http://([^/]+/*)+");
	private final String ICON_PATH = "/data/data/com.android.techpre/icons";
	
	private static DownloadRecordEntityManager mDownloadRecordEntityManager;
	private static HashMap<Integer,DownloadTask> mDownloadTasks=new HashMap<Integer, DownloadTask>();
	private static HashMap<String,OnTaskChangeListener> mOnTaskChangeListeners=new HashMap<String, DownloadManager.OnTaskChangeListener>();
	private String mPath=APP_PATH;
	private static DownloadManager sInstance; 
	private DownloadManager(){}
	
	/**
	 * 单例获得实例
	 * @param context
	 * @return
	 */
	public synchronized static DownloadManager getInstance(Context context){
		if(sInstance==null){
			sInstance=new DownloadManager(context);
			loadTasks();
		}
		return sInstance;
	}
	
	public interface OnTaskChangeListener {
		void onTaskProgressUpdate(DownloadTask downloadTask);
		void onTaskStateUpdate(int state, DownloadTask downloadTask);
	}
	
	/**
	 * 设置任务变化监听器
	 * @param onTaskChangeListener
	 */
	public void addOnTaskChangeListener(String tag,OnTaskChangeListener onTaskChangeListener){
		mOnTaskChangeListeners.put(tag, onTaskChangeListener);
	}
	
	private static OnChangeListener mOnChangeListener=new OnChangeListener() {

		@Override
		public void onProgressUpdate(DownloadTask downloadTask) {
			DownloadEntry downloadEntry =downloadTask.getDownloadEntry();
			mDownloadRecordEntityManager.updateDownload(downloadEntry);
			Iterator<OnTaskChangeListener> i=mOnTaskChangeListeners.values().iterator();
			while(i.hasNext())
				i.next().onTaskProgressUpdate(downloadTask);
		}

		@Override
		public void onStateUpdate(int state, DownloadTask downloadTask) {
			DownloadEntry downloadEntry =downloadTask.getDownloadEntry();
			if(state==DownloadTask.STATE_DELETE||state==DownloadTask.STATE_DELETE_WITH_FILE){
				mDownloadRecordEntityManager.dropDownload(downloadEntry.getId());
				mDownloadTasks.remove(downloadEntry.getId());
				File f=new File(downloadTask.getDownloadEntry().getPath());
				f.delete();
			} else
				mDownloadRecordEntityManager.updateDownload(downloadEntry);
			
			Iterator<OnTaskChangeListener> i=mOnTaskChangeListeners.values().iterator();
			while(i.hasNext())
				i.next().onTaskStateUpdate(state, downloadTask);
		}
	};

	/**
	 * 实例构造函数
	 * @param context
	 */
	private DownloadManager(Context context) {
		mDownloadRecordEntityManager=DownloadRecordEntityManager.getInstance();
		File temp=new File(mPath);
		if(!temp.exists())
			temp.mkdirs();
		temp=new File(ICON_PATH);
		if(!temp.exists())
			temp.mkdirs();
	}

	/**
	 * 设置路径
	 * @param path
	 */
	public void setPath(String path){
		mPath=path;
	}
	
	/**
	 * 获得路径
	 */
	public String getPath(){
		return mPath;
	}
	
	/**
	 * 从数据库读取下载任务
	 * @return
	 */
	private synchronized static ArrayList<DownloadEntry> loadTasks() {
		Cursor cursor=mDownloadRecordEntityManager.getAllDowloads();
		ArrayList<DownloadEntry> entrys=new ArrayList<DownloadEntry>();
		while(cursor.moveToNext()){
			int id=cursor.getInt(cursor.getColumnIndex(DownloadRecordEntity._ID));
			DownloadEntry downloadEntry=new DownloadEntry(
					id,
					cursor.getString(cursor.getColumnIndex(DownloadRecordEntity.RESOURCE_ID)),
					cursor.getString(cursor.getColumnIndex(DownloadRecordEntity.URL)),
					cursor.getString(cursor.getColumnIndex(DownloadRecordEntity.MEDIA_URI)),
					cursor.getInt(cursor.getColumnIndex(DownloadRecordEntity.MIME_TYPE)),
					cursor.getString(cursor.getColumnIndex(DownloadRecordEntity.FILE_NAME)),
					cursor.getString(cursor.getColumnIndex(DownloadRecordEntity.LOCAL_PATH)),
					cursor.getLong(cursor.getColumnIndex(DownloadRecordEntity.LASTMOD)),
					cursor.getInt(cursor.getColumnIndex(DownloadRecordEntity.TOTAL_BYTES)),
					cursor.getInt(cursor.getColumnIndex(DownloadRecordEntity.CURRENT_BYTES)),
					cursor.getString(cursor.getColumnIndex(DownloadRecordEntity.ICON_NAME))
					);
			entrys.add(downloadEntry);
			DownloadTask downloadTask =new DownloadTask(downloadEntry);
			downloadTask.setOnTaskChangeListener(mOnChangeListener);
			mDownloadTasks.put(id,downloadTask);
		}
		cursor.close();
		return entrys;
	}
	
	/**
	 * 获得任务状态
	 * @param id <br>
	 * @return DownloadTask中的STATE
	 */
	public synchronized int getTaskState(int id){
		return mDownloadTasks.get(id).getState();
	}
	
	/**
	 * 仅删除任务
	 * @param id
	 */
	public synchronized void deleteTask(int id){
		mDownloadTasks.get(id).delete();
	}
	
	/**
	 * 删除任务和文件
	 * @param id
	 */
	public synchronized void deleteTaskWithFile(int id){
		mDownloadTasks.get(id).deleteWithFile();
	}
	
	/**
	 * 任务开始下载
	 * @param id
	 */
	public synchronized void startTask(int id){
		mDownloadTasks.get(id).start();
	}
	
	/**
	 * 重新开始任务
	 * @param id
	 */
	public synchronized void restartTask(int id){
		mDownloadTasks.get(id).restart();
	}
	
	/**
	 * 停止任务
	 * @param id
	 */
	public synchronized void stopTask(int id){
		mDownloadTasks.get(id).stop();
	}

	/**
	 * 获得所有下载任务
	 * @return
	 */
	public HashMap<Integer,DownloadTask> getDownloadTasks(){
		return mDownloadTasks;
	}
	
	/**
	 * 增加任务并自动开始下载
	 * @param resourceId
	 * @param url
	 * @param mediaUri
	 * @param mimeType
	 * @param fileName
	 * @param iconName
	 * @return
	 */
	public synchronized DownloadEntry addTask(String resourceId,String url,String mediaUri,int mimeType,String fileName,String iconName) {
		if (!isUriValid(url))
			return null;
		if(!isStringValid(fileName))
			fileName=parseFileName(url);
		String suffix=".apk";
		if(mimeType==2)
			suffix=".mp3";
		File temp=new File(mPath,getValidFileName(fileName+suffix));
		try {
			temp.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		DownloadEntry downloadEntry=new DownloadEntry(0, resourceId,url,mediaUri,mimeType, fileName, mPath+fileName+suffix, System.currentTimeMillis(), -1, 0, iconName);
		int id=mDownloadRecordEntityManager.addDownload(downloadEntry);
		downloadEntry.setId(id);
		DownloadTask downloadTask =new DownloadTask(downloadEntry);
		downloadTask.setOnTaskChangeListener(mOnChangeListener);
		mDownloadTasks.put(id,downloadTask);
		downloadTask.start();
		return downloadEntry;
	}
	
	/**
	 * 检测URL是否已经存在任务中
	 * @param url
	 * @return 如果已经存在，返回相应的DownloadEntry,否则返回null
	 */
	public DownloadEntry isTaskExists(String url){
		Set<Entry<Integer, DownloadTask>> sets=mDownloadTasks.entrySet();
		for(Entry<Integer, DownloadTask> e:sets){
			if(e.getValue().getDownloadEntry().getUrl().equals(url))
				return e.getValue().getDownloadEntry();
		}
		return null;
	}
	
	/**
	 * 根据URI解析获得要下载的文件名
	 * @param uriPath
	 * @return
	 */
	private String parseFileName(String uriPath) {
		String result = null;
		int start = uriPath.lastIndexOf('/');
		int end = uriPath.lastIndexOf('?');
		if (end > start)
			result = uriPath.substring(start + 1, end);
		else {
			String temp = uriPath.substring(start + 1);
			if (temp.trim().equals(""))
				result = "index.html";
			else
				result = temp;
		}
		return result;
	}
	
	/**
	 * 获得合法的文件名
	 * @param fileName
	 * @return
	 */
	private String getValidFileName(String fileName) {
		char invalidChar[] = { '*', '\\', '|', '"', '\'', '/', '<', '>', '?' };
		for (char c : invalidChar)
			fileName = fileName.replace(c, '\0');
		if (!isStringValid(fileName.trim()))
			fileName = "index.html";
		if (!new File(mPath, fileName).exists())
			return fileName;
		int dot = fileName.lastIndexOf('.');
		String mainName = null;
		String suffix = "";
		if (dot != -1) {
			suffix = fileName.substring(dot);
			mainName = fileName.substring(0, dot);
		} else
			mainName = fileName;
		final Pattern p = Pattern.compile("^" + mainName
				+ "\\(([2-9]|([1-9]+\\d*))\\)" + suffix);
		File dir = new File(mPath);
		String matches[] = dir.list(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String filename) {
				Matcher m = p.matcher(filename);
				return m.matches();
			}
		});
		ArrayList<Integer> indexs = new ArrayList<Integer>();
		int count = DUPLICATE_BEGIN_INDEX;
		for (String m : matches) {
			int left = m.lastIndexOf('(');
			int right = m.lastIndexOf(')');
			indexs.add(Integer.parseInt(m.substring(left + 1, right)));
		}
		Collections.sort(indexs);
		for (Integer i : indexs) {
			if (i >= DUPLICATE_BEGIN_INDEX && i <= count)
				count = i + 1;
		}
		return mainName + "(" + count + ")" + suffix;
	}
	
	/**
	 * 检测字符串是否合法
	 * @param string
	 * @return
	 */
	private boolean isStringValid(String string) {
		if (string == null || string.trim().equals(""))
			return false;
		return true;
	}
	
	/**
	 * 检测URI是否合法
	 * @param uriPath
	 * @return
	 */
	private boolean isUriValid(String uriPath) {
		Matcher m = fPattern.matcher(uriPath);
		return m.matches();
	}
}
